﻿module CardFunctions

open Lambda
open Combinators

//let varAllocator = VariableAllocator()
//let newVar() = Variable(CEvar(varAllocator.Alloc()))

let var name = Variable(CEvar(name))

let zero = var "zero"
let succ = var "succ"
let dbl = var "dbl"
let get = var "get"
let put = var "put"
let inc = var "inc"
let dec = var "dec"
let attack = var "attack"
let help = var "help"
let copy = var "copy"
let revive = var "revive"
let zombie = var "zombie"



let (||>) a b = Lapp(b, a)
let test() =
    // test order
    assert(zero ||> succ = Lapp(succ, zero))
    // test associativity
    assert(zero ||> succ ||> succ = Lapp(succ, Lapp(succ, zero)))

// let private iarg = newVar()
let I =
    //Tlambda(iarg, Variable iarg)
    Variable IEcomb

let S =
    Variable SEcomb
//    let f, g, x = newVar(), newVar(), newVar()
//    let expr =
//        (g ||> x)
//        ||> (f ||> x)
//    Tlambda(f.Var, Tlambda(g.Var, Tlambda(x.Var, expr)))

let K =
    Variable KEcomb
//    let i, j = newVar(), newVar()
//    let expr = i
//    Tlambda(i.Var, Tlambda(j.Var, expr))

let Y =
    let f, x = var "f", var "x"
    let expr =
        Tlambda(x.Var, (x ||> x) ||> f)
        ||> Tlambda(x.Var, (x ||> x) ||> f)
    Tlambda(f.Var, expr)
//    Tlambda(0,
//        Lapp((Tlambda(1, Lapp(Variable 0, Lapp(Variable 1, Variable 1)))),
//            Tlambda(1, Lapp(Variable 0, Lapp(Variable 1, Variable 1)))))

let apply =
    let f, x = var "f", var "x"
    Tlambda(f.Var, Tlambda(x.Var, x ||> f))

/// equivalent to (f i; i)
let call = Variable Combinators.KEcomb ||> Variable Combinators.SEcomb
//    let f, x = newVar(), newVar()
//    let expr = x ||> (f ||> ())
//    Tlambda(f.Var, Tlambda(x.Var, expr))

//let infloopSF infloop f i =
//    infloop f (call f i)

// S f g x = (f x) (g x)
// S K f i = (K i) (f i)               

let infloopS =
    let loop, f, i = var "loop", var "f", var "i"
    let expr =
        i ||> (f ||> call)
        ||> (f ||> loop)
    Tlambda(loop.Var, Tlambda(f.Var, Tlambda(i.Var, expr)))

//let loopS loop f start =
//    loop f (succ(call f start))

let loopS =
    let loop, f, i = var "loop", var "f", var "i"
    let expr =
        i ||> (f ||> call)
        ||> succ
        ||> (f ||> loop)
    Tlambda(loop.Var, Tlambda(f.Var, Tlambda(i.Var, expr)))

let loop = loopS ||> Y
let infloop = infloopS ||> Y

let helpiii =
    let i = var "i"
    Tlambda(i.Var, i ||> (i ||> (i ||> help)))

let helpiin =
    let i, n = var "i", var "n"
    Tlambda(n.Var, Tlambda(i.Var, n ||> (i ||> (i ||> help))))

// let megaheali 